package com.lee.wordcounter.impl;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import com.lee.wordcounter.WordCounter;
import com.lee.wordcounter.utils.Timer;
import com.lee.wordcounter.utils.WordCounterUtils;
/**
 * Reads words from a file, then rank them based on frequency of appearance.
 * 
 * @author Liyan Zhao
 *
 */
public class ArrayListWordCounter implements WordCounter {
	// Initial values for ArraList length
	public static final int INIT_ROW_LENGTH = 200;
	public static final int INIT_NUM_ROWS = 50;
	// Regular expression to remove non-alphabetic chars
	public static final String NON_ALPHABETIC_EXP = "[^\\p{L}]";
    // Two dimension ArrayList, all words with the same count are stored in one list. Multiple of these
	// lists make up the count matrix
    private final ArrayList<ArrayList<String>> wordCount = new ArrayList <ArrayList<String>> (INIT_NUM_ROWS);
    // Empty string constant
    private final static String EMPTY_STRING = "";
    
    
	@Override
	public String[] getTopRankedWords(int rank) {
		// TODO Auto-generated method stub
		ArrayList <String> ret = new ArrayList <String> (INIT_ROW_LENGTH);
		int size = wordCount.size();
		int index = 0;
		int count = 0;
		while ((index < size) && (count < rank)) {
			ArrayList <String> row = wordCount.get(size - 1 - index);
			if (!row.isEmpty()) {
				ret.addAll(row);
				count ++;
			}
			index ++;
		}
		return ret.toArray(new String [0]);
	}
	/**
	 * Populates the word counter double ArrayList. Moving the word to the next row if
	 * it's found, else add it to the first row. The words in the last row are the ones with 
	 * highest frequency of appearance.
	 */
	@Override
	public void processWords(String fileName) {
		// TODO Auto-generated method stub
		try {
			BufferedReader br= new BufferedReader(new FileReader(fileName));
			String line = br.readLine();
			while (line != null) {
				String [] tokens= line.split(" ");
				for (String s : tokens) {
					addWord(s);
				}
				line = br.readLine();
			}
			br.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}        
	}


	/**
	 * Adds a word to the word counter structure
	 * 
	 * @param word
	 */
	private void addWord(String word) {
		// remove non-alphabetic chars
		word = word.replaceAll(NON_ALPHABETIC_EXP, EMPTY_STRING);
		// store the word to be added to the next row
		String temp = EMPTY_STRING;
		// if the word is found in the existing lists
		boolean found = false;
		for (ArrayList<String> row : wordCount) {
			// adds temp to the next row if it's set
			if (!temp.equals(EMPTY_STRING)) {
				row.add(temp);
				temp = EMPTY_STRING;
			}
			// if the word is present in the current row
			if (row.contains(word)) {
				// remove it from the current row
				row.remove(word);
				temp = word; 
				found = true;
			}
		}
		// if the word is to be promoted to the next row, that's not created yet
		if (found &&(!temp.equals(EMPTY_STRING))) {
			// create the next row
			ArrayList <String> nextRow = new ArrayList<String>(INIT_ROW_LENGTH);
			nextRow.add(temp);
			// add the row to the outer list
			wordCount.add(nextRow);
		}
		// if the word is not present in the current structure
		if (!found) {
			// if there's no row at present
			if (wordCount.size() ==0) {
				ArrayList <String> nextRow = new ArrayList<String>(INIT_ROW_LENGTH);
				// adds the new row to the outer list
				wordCount.add(nextRow);
			}
			// add it to the first row
		    wordCount.get(0).add(word);
		}
	}
	

	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub


       
	}

}
